////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 CORE Solutions Limited
// All rights reserved.
// PROPRIETARY AND CONFIDENTIAL INFORMATION.
// Use is subject to license terms.
//
// FUNCTION ID      :   
// AUTHOR           :    
// DATE CREATE      :   
// DESCRIPTION      :   
//                  :   
//                  :   
//                  :   
//
// MODIFICATION HISTORY:
// DATE         AUTHOR          VERSION NO.         COMMENT
// -----------  --------------  ------------------  -------------------
// 2006/04/26   Ric Yik         1.0                 BugZilla #5534
// 2006/06/23   Ric Yik         1.0                 BugZilla #5535
//
//
////////////////////////////////////////////////////////////////////////////////

package com.erp.framework.controller.form;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;

import com.erp.framework.SimpleConstants;
import com.erp.framework.model.schema.TableSchema;
import com.erp.framework.pagination.PageControl;
import com.erp.framework.util.CommonUtil;
import com.erp.framework.util.logger.Logger;
import com.erp.framework.util.mainmenu.MenuObject;

public abstract class SimpleCoreForm extends SimpleBaseForm {

    protected int originalIdx;
    protected String actionIdx;

    protected ArrayList menuGroupList = new ArrayList();
    protected String isReadOnly = GENERIC_NO;
    protected String backTo = "";
    protected String roCaller = ""; // which module call me to be readonly
    protected String openingParent = "";
    private final int MAX_DIM = 20;
    protected ArrayList multiRows[] = new ArrayList[MAX_DIM];
    protected Class[] multiRowClazz = new Class[MAX_DIM];
    protected String idx[][] = new String[MAX_DIM][];
    protected String rowMode[][] = new String[MAX_DIM][];
    protected String isDelete[][] = new String[MAX_DIM][];
    protected String scrollTo[] = new String[MAX_DIM];
    protected Object oldValues;
    protected TableSchema ts;
    protected String tsName;
    protected TableSchema[] childTs;    
    protected String[] childTsNames;
    protected String formType;
    protected ArrayList webLabelList;
    protected PageControl pageControl = null;
    protected HashMap errMsgMap;
    protected String sysLangCode;

    protected Map menuObjectActionMap = new HashMap();

    public ArrayList getWebLabelList() {
        return webLabelList;
    }

    public void setWebLabelList(ArrayList webLabelList) {
        this.webLabelList = webLabelList;
    }

    public TableSchema[] getChildTs() {
        return childTs;
    }

    public void setChildTs(TableSchema[] childTs) {
        this.childTs = childTs;
    }

    public String[] getChildTsNames() {
        return childTsNames;
    }

    public void setChildTsNames(String[] childTsNames) {
        this.childTsNames = childTsNames;
    }

    public TableSchema getTs() {
        return ts;
    }

    public void setTs(TableSchema ts) {
        this.ts = ts;
    }

    public String getTsName() {
        return tsName;
    }

    public void setTsName(String tsName) {
        this.tsName = tsName;
    }

    public SimpleCoreForm() {

        for (int i = 0; i < MAX_DIM; i++) {
            multiRows[i] = new ArrayList();
        }
    }

    public SimpleCoreForm(Class multiRowClazz) {

        for (int i = 0; i < MAX_DIM; i++) {
            multiRows[i] = new ArrayList();
        }
        this.multiRowClazz[currIdx] = multiRowClazz;
    }

    public ArrayList getMenuGroupList() {
        return menuGroupList;
    }

    public void setMenuGroupList(ArrayList menuGroupList) {
        this.menuGroupList = menuGroupList;
    }

    public String getIsReadOnly() {

        return isReadOnly;
    }

    public void setIsReadOnly(String isReadOnly) {

        this.isReadOnly = isReadOnly;
    }

    public String getOpeningParent() {

        return openingParent;
    }

    public void setOpeningParent(String openingParent) {

        this.openingParent = openingParent;
    }

    // Menu Object List (e.g. button)
    protected ArrayList menuObjectList = new ArrayList();

    public ArrayList getMenuObjectList() {
        return menuObjectList;
    }

    public void setMenuObjectList(ArrayList menuObjectList) {
        if (this.menuObjectList != menuObjectList) {
            this.menuObjectActionMap.clear();
            if (menuObjectList != null) {
                for (int i = 0; i < menuObjectList.size(); ++i) {
                    MenuObject obj = (MenuObject) menuObjectList.get(i);
                    if (!CommonUtil.isEmpty(obj.getObjectAction())) {
                        this.menuObjectActionMap.put(obj.getObjectAction(), obj);
                    }
                }
            }
        }
        this.menuObjectList = menuObjectList;
    }

    public MenuObject getMenuObjectByObjectAction(String objectAction) {
        if (CommonUtil.isEmpty(objectAction)) return null;
        if (menuObjectActionMap.containsKey(objectAction)) return (MenuObject) menuObjectActionMap.get(objectAction);
        for (int i = 0; i < menuObjectList.size(); ++i) {
            MenuObject obj = (MenuObject) menuObjectList.get(i);
            if (objectAction.equals(obj.getObjectAction())) {
                this.menuObjectActionMap.put(obj.getObjectAction(), obj);
                return obj;
            }
        }
        return null;
    }

    // NOT intended to be overridden by subclasses
    protected final void coreValidate(ActionErrors errors) {
        baseCoreValidate(errors); // Simply invoke parent baseCoreValidate if
        // no changes
    }

    // NOT intended to be overridden by subclasses
    protected final void coreReset(ActionMapping mapping, HttpServletRequest request) {
        baseCoreReset(mapping, request); // Simply invoke parent
        // baseCoreReset if no changes
    }

    public String getRoCaller() {

        return roCaller;
    }

    public void setRoCaller(String roCaller) {

        this.roCaller = roCaller;
    }

    public String getBackTo() {
        return backTo;
    }

    public void setBackTo(String backTo) {
        this.backTo = backTo;
    }

    public String[] getIdx() {

        return this.idx[currIdx];
    }

    public String[] getRowMode() {

        return this.rowMode[currIdx];
    }

    public String[] getIsDelete() {

        return this.isDelete[currIdx];
    }

    public void setIdx(String[] idx) {

        this.idx[currIdx] = idx;
    }

    public void setRowMode(String[] rowMode) {

        this.rowMode[currIdx] = rowMode;
    }

    public void setIsDelete(String[] isDelete) {

        this.isDelete[currIdx] = isDelete;
    }

    protected int sidx[] = new int[MAX_DIM];

    public int getSidx() {

        return sidx[currIdx];
    }

    public void setSidx(int sidx) {

        this.sidx[currIdx] = sidx;
    }

    protected int currIdx = 0;

    public int getCurrIdx() {

        return this.currIdx;
    }

    public void setCurrIdx(int inIdx) {

        this.currIdx = inIdx;
    }

    public String getAction() {

        return "";
    }

    public Object getOldValues() {

        return this.oldValues;
    }

    public String getDeleteIdx() {

        return null;
    }

    public void setOldValues(Object oldValues) {
        this.oldValues = oldValues;
    }

    public void setMode(String mode) {

    }

    public Class getMultiRowClazz() {

        return this.multiRowClazz[currIdx];
    }

    public void setMultiRows(ArrayList multiRows) {

        this.multiRows[currIdx] = multiRows;
    }

    public void setMultiRowClazz(Class multiRowClazz) {

        this.multiRowClazz[currIdx] = multiRowClazz;
    }

    public ArrayList getMultiRows() {

        if (this.multiRows[currIdx].size() > 0) {
            return this.multiRows[currIdx];
        } else {
            return getRows();
        }
    }

    public ArrayList getMultiRows(int selectedIdx) {

        if (selectedIdx < MAX_DIM)
            return this.multiRows[selectedIdx];
        else
            return null;
    }

    public void addRow() {
        try {
            this.addRow(this.multiRowClazz[currIdx].newInstance());
        } catch (Exception e) {
            if (Logger.isDebugLevel()) {
                Logger.logExceptions(this, e);
            }
        }
    }

    public void addRow(Object rowToAdd) {

        try {
            PropertyUtils.setSimpleProperty(rowToAdd, "idx", Integer.toString(this.multiRows[currIdx].size()));
            PropertyUtils.setSimpleProperty(rowToAdd, "rowMode", ROW_MODE_CREATE);
            this.setRowToAddTs(rowToAdd);
            this.multiRows[currIdx].add(rowToAdd);
        } catch (ArrayIndexOutOfBoundsException ae) {
            throw new RuntimeException(ae.getMessage());
        } catch (Exception e) {
            if (Logger.isDebugLevel()) {
                Logger.logExceptions(this, e);
            }
        }
    }

    protected void setRowToAddTs(Object rowToAdd) throws Exception {
        PropertyUtils.setSimpleProperty(rowToAdd, "ts", this.ts);
        PropertyUtils.setSimpleProperty(rowToAdd, "tsName", this.tsName);
    }

    public void deleteRow(int delIdx) {

        try {
            Object row = multiRows[currIdx].get(delIdx);
            PropertyUtils.setSimpleProperty(row, "isDelete", "checked");
            multiRows[currIdx].set(delIdx, row);
        } catch (Exception e) {
            if (Logger.isDebugLevel()) {
                Logger.logExceptions(this, e);
            }
        }
    }

    public ArrayList getFinalRows() {

        return getRows();
    }

    protected ArrayList getRows() {
        Logger.debug(this, "*** getRows() currIdx: " + currIdx);
        try {
            if (idx == null || idx[currIdx] == null)
                return multiRows[currIdx];

            // Get the mapping first
            int currLen = idx[currIdx].length;
            int[] mapping = new int[currLen];
            for (int i = 0; i < currLen; i++) {
                mapping[i] = Integer.parseInt(idx[currIdx][i]);
                PropertyUtils.setSimpleProperty(multiRows[currIdx].get(mapping[i]), "isDelete", "");
            }

            PropertyDescriptor fields[] = PropertyUtils.getPropertyDescriptors(this);

            String isDelName = "isDelete";
            int isDelLen = 0;
            if (this.isDelete[currIdx] != null) {
                isDelLen = this.isDelete[currIdx].length;
            }

            for (int i = 0; i < fields.length; i++) {
                String name = fields[i].getName();
                if (fields[i].getPropertyType() != null && fields[i].getPropertyType().isArray() && !name.equals(isDelName)) {

                    try {
                        Object values[] = (Object[]) PropertyUtils.getSimpleProperty(this, name);
                        if (values == null) {
                            continue;
                        }

                        int valLen = values.length;
                        int lastIdx = 0;

                        for (int x = 0, k = -1; x < currLen; x++) {
                            boolean isRowDel = false;
                            if (isDelLen > 0) {
                                for (int y = 0; y < isDelLen; y++) {
                                    int isDelIdx = Integer.parseInt(this.isDelete[currIdx][y]);
                                    if (mapping[x] == isDelIdx) {
                                        isRowDel = true;
                                        break;
                                    }
                                }
                            }

                            if (valLen >= currLen) {
                                lastIdx = x;
                            } else {
                                if (isRowDel)
                                    continue;
                            }

                            k = mapping[x];

                            if (k > multiRows[currIdx].size() - 1) {
                                Logger.debug(this, "!!!! Should never happen! [property='" + name + "(" + lastIdx + ")', " + k
                                        + "/" + multiRows[currIdx].size() + "]");
                            } else {
                                MultiRow mRow = (MultiRow) multiRows[currIdx].get(k);
                                PropertyUtils.setSimpleProperty(mRow, name, values[lastIdx]);
                                multiRows[currIdx].set(k, mRow);
                            }

                            if (valLen < currLen) {
                                lastIdx++;
                            }
                        }
                    } catch (Exception e) {
                    }
                }
            }

            if (this.isDelete[currIdx] != null) {
                Logger.debug(this, "* Size of delete array = " + isDelete[currIdx].length);
                for (int i = 0, delIdx; i < this.isDelete[currIdx].length; i++) {
                    delIdx = Integer.parseInt(this.isDelete[currIdx][i]);
                    Object row = multiRows[currIdx].get(delIdx);
                    PropertyUtils.setSimpleProperty(row, "isDelete", "checked");
                    multiRows[currIdx].set(delIdx, row);
                }
            }

        } catch (Exception e) {
            if (Logger.isDebugLevel()) {
                Logger.logExceptions(this, e);
            }
        }
        return multiRows[currIdx];
    }

    public void setRow(int idx, Object mRow) {

        try {
            PropertyUtils.setSimpleProperty(mRow, "idx", Integer.toString(idx));
            if (idx > this.multiRows[currIdx].size() - 1) {
                this.multiRows[currIdx].add(mRow);
            } else {
                this.multiRows[currIdx].set(idx, mRow);
            }
        } catch (Exception e) {
            if (Logger.isDebugLevel()) {
                Logger.logExceptions(this, e);
            }
        }
    }

    public int getTotalPage() {

        int tPage = (int) (multiRows[currIdx].size() / SimpleConstants.MAX_DISPLAY);
        if (multiRows[currIdx].size() % SimpleConstants.MAX_DISPLAY != 0)
            tPage += 1;
        return tPage;
    }

    public int getCurrentPage() {

        int cPage = (int) ((sidx[currIdx] + 1) / SimpleConstants.MAX_DISPLAY);
        if ((sidx[currIdx] + 1) % SimpleConstants.MAX_DISPLAY != 0)
            cPage += 1;
        return cPage;
    }

    public String getLastPageSidx() {
        return String.valueOf((getTotalPage() - 1) * SimpleConstants.MAX_DISPLAY);
    }

    public boolean isFirstPage() {
        int page = getCurrentPage();

        return page == 1;
    }

    public boolean isLastPage() {
        int page = getCurrentPage();

        return page == getTotalPage();
    }

    public String getScrollTo() {
        return scrollTo[currIdx];
    }

    public void setScrollTo(String scrollTo) {
        this.scrollTo[currIdx] = scrollTo;
    }

    public String getFormType() {
        return formType;
    }

    public void setFormType(String formType) {
        this.formType = formType;
    }

    public PageControl getPageControl() {
        return pageControl;
    }

    public void setPageControl(PageControl pageControl) {
        this.pageControl = pageControl;
    }

	public HashMap getErrMsgMap() {
		return errMsgMap;
	}

	public void setErrMsgMap(HashMap errMsgMap) {
		this.errMsgMap = errMsgMap;
	}

	public String getSysLangCode() {
		return sysLangCode;
	}

	public void setSysLangCode(String sysLangCode) {
		this.sysLangCode = sysLangCode;
	}

    public int getOriginalIdx() {
        return originalIdx;
    }

    public void setOriginalIdx(int originalIdx) {
        this.originalIdx = originalIdx;
    }

    public String getActionIdx() {
        return actionIdx;
    }

    public void setActionIdx(String actionIdx) {
        this.actionIdx = actionIdx;
    }

    public boolean isReadOnly() {
        return SimpleConstants.GENERIC_YES.equals(this.getIsReadOnly());
    }

}
